﻿using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AbpOne.Application.Contracts.Wallpaper;
using AbpOne.Domain.Shared.Enum;
using AbpOne.Domain.Wallpaper;
using AbpOne.Domain.Wallpaper.Repositories;
using AbpOne.ToolKits.Extensions;
using HtmlAgilityPack;

namespace AbpOne.BackgroundJobs.Jobs.WallpaperCrawl {
    public class WallpaperJob : IBackgroundJob {
        private readonly IWallpaperRepository _wallpaperRepository;

        public WallpaperJob(IWallpaperRepository wallpaperRepository) {
            _wallpaperRepository = wallpaperRepository;
        }

        public async Task ExecuteAsync() {
            var wallpaperUrls = new List<WallpaperJobItem<string>> {
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_1_1.html", Type = WallpaperEnum.Beauty
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_58_1.html", Type = WallpaperEnum.Sportsman
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_66_1.html", Type = WallpaperEnum.CuteBaby
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_4_1.html", Type = WallpaperEnum.Emotion
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_3_1.html", Type = WallpaperEnum.Landscape
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_9_1.html", Type = WallpaperEnum.Animal
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_13_1.html", Type = WallpaperEnum.Plant
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_64_1.html", Type = WallpaperEnum.Food
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_11_1.html", Type = WallpaperEnum.Movie
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_5_1.html", Type = WallpaperEnum.Anime
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_34_1.html", Type = WallpaperEnum.HandPainted
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_65_1.html", Type = WallpaperEnum.Text
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_2_1.html", Type = WallpaperEnum.Creative
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_10_1.html", Type = WallpaperEnum.Car
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_14_1.html", Type = WallpaperEnum.PhysicalEducation
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_63_1.html", Type = WallpaperEnum.Military
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_17_1.html", Type = WallpaperEnum.Festival
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_15_1.html", Type = WallpaperEnum.Game
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_12_1.html", Type = WallpaperEnum.Apple
                },
                new WallpaperJobItem<string> {
                    Result = "https://www.i4.cn/wper_4_19_7_1.html", Type = WallpaperEnum.Other
                }
            };

            // 先new一个HtmlWeb对象，我们主要用这个对象去加载我们的URL
            var web = new HtmlWeb();
            var listTask = new List<Task<WallpaperJobItem<HtmlDocument>>>();

            // 循环处理 wallpaperUrls，等待所有请求完成。这样就拿到了20个HtmlDocument，和它的分类，接下来就可以去处理 listTask 就行了
            wallpaperUrls.ForEach(item => {
                var task = Task.Run(async () => {
                    // web.LoadFromWebAsync(...)，它会返回一个HtmlDocument对象，这样就和上面的list_task对应起来，
                    // 从而也应证了前面添加的WallpaperJobItem是通用的一个待抓项的类
                    var htmlDocument = await web.LoadFromWebAsync(item.Result);
                    return new WallpaperJobItem<HtmlDocument> {
                        Result = htmlDocument,
                        Type = item.Type
                    };
                });
                listTask.Add(task);
            });
            Task.WaitAll(listTask.ToArray());


            var wallpapers = new List<Wallpaper>();


            // 在 foreach 循环中先拿到当前循环的Item对象，即WallpaperJobItem<HtmlDocument>
            foreach (var list in listTask) {
                var item = await list;

                // 通过.DocumentNode.SelectNodes()语法获取到图片列表，因为在a标签下面有两个img标签，取第一个即可
                var imgs = item.Result.DocumentNode
                    .SelectNodes("//article[@id='wper']/div[@class='jbox']/div[@class='kbox']/div/a/img[1]").ToList();
                imgs.ForEach(x => {
                    wallpapers.Add(new Wallpaper {
                        // GetAttributeValue()是HtmlAgilityPack的扩展方法，用于直接获取属性值。
                        Url = x.GetAttributeValue("data-big", ""),
                        Title = x.GetAttributeValue("title", ""),
                        Type = (int) item.Type,
                        CreateTime = x.Attributes["data-big"].Value.Split("/").Last().Split("_").First().TryToDateTime()
                    });
                });
            }
            
            // 插入数据库
            // 因为抓取的图片可能存在重复的情况，我们需要做一个去重处理，先查询到数据库中的所有的URL列表，
            // 然后在判断抓取到的url是否存在，最后调用BulkInsertAsync(...)批量插入方法
            var urls = (await _wallpaperRepository.GetListAsync()).Select(x => x.Url);
            wallpapers = wallpapers.Where(x => !urls.Contains(x.Url)).ToList();
            if (wallpapers.Any())
            {
                await _wallpaperRepository.BulkInsertAsync(wallpapers);
            }
        }
    }
}